#ifndef __APPLI_CORE_ALE_NS_H
#define __APPLI_CORE_ALE_NS_H 1

#include <life/options.hpp>
#include <life/lifecore/application.hpp>

#include <navierstokes.hpp>

namespace Life
{


    inline
    Life::po::options_description
    makeOptionsNSALE()
    {
        Life::po::options_description stokesoptions("Stokes options");
        stokesoptions.add_options()
            //        ("penalS", Life::po::value<double>()->default_value( 0.5 ), "penalisation speed parameter")
            //        ("penalP", Life::po::value<double>()->default_value( 0.5 ), "penalisation presure parameter")
            ("entree-v", Life::po::value<double>()->default_value( 1.0 ), "vitesse d entree")
            ("sortie-v", Life::po::value<double>()->default_value( 1.0 ), "vitesse de sortie")
            ("sortie-p", Life::po::value<double>()->default_value( 0.0 ), "pression imposee sur la sortie")
            ("entree-p", Life::po::value<double>()->default_value( 0.0 ), "pression imposee sur l'entree")
            ("rho", Life::po::value<double>()->default_value( 1.0 ), "masse volumique")
            ("mu", Life::po::value<double>()->default_value( 1.0 ), "reaction coefficient component")
            ("hsize", Life::po::value<double>()->default_value( 0.5 ), "first h value to start convergence")
            ("bccoeff", Life::po::value<double>()->default_value( 10.0 ), "coeff for weak Dirichlet conditions")
            ("f0", Life::po::value<double>()->default_value( 0.0 ), "f0")
            ("stab", Life::po::value<int>()->default_value( 0 ), "0 = Non, 1 = oui")
            ("stat", Life::po::value<int>()->default_value( 0 ), "0 = Non, 1 = oui")
            ("coef-err", Life::po::value<double>()->default_value( 1e-5 ), "Coeferr")
            ("mesh", Life::po::value<std::string>()->default_value( "ola" ), "0 = stationnaire, 1 = instationnaire")
            ("dt", Life::po::value<double>()->default_value( 0.1 ), "dt")
            ("Tfinal", Life::po::value<double>()->default_value( 1.0 ), "Temps final")
            ("export", "export results(ensight, data file(1D)")
            ("export-matlab", "export matrix and vectors in matlab" )
            ;
        return stokesoptions.add( Life::life_options() ) ;
    }


    /**
     * This routine defines some information about the application like
     * authors, version, or name of the application. The data returned is
     * typically used as an argument of a Life::Application subclass.
     *
     * \return some data about the application.
     */
    inline
    Life::AboutData
    makeAboutNSALE()
    {
        Life::AboutData about( "MonStokes" ,
                               "monstokes" ,
                               "0.1",
                               "Stokes equation on simplices or simplex products",
                               Life::AboutData::License_GPL,
                               "Copyright (c) 2009 Universite de Grenoble 1 (Joseph Fourier)");

        about.addAuthor("Vincent Chabannes", "developer", "vincent.chabannes@imag.fr", "");
        return about;

    }


    class Core_Ns_ALE
    {
    public :

        static const int nDim = 2;
        static const int nOrder = 2;

        typedef Application application_type;
        typedef boost::shared_ptr< application_type> application_ptrtype;

        typedef Life::NavierStokes<nDim, nOrder, Simplex> NavierStokes_type;
        typedef boost::shared_ptr<NavierStokes_type> NavierStokes_ptrtype;

        Core_Ns_ALE(int argc, char** argv)
            :
            M_application(new application_type(argc,
                                               argv,
                                               makeAboutNSALE(),
                                               makeOptionsNSALE()
                                               )),
            M_Ti( M_application->vm()["bdf-time-initial"].as<double>() ),
            M_Tf( M_application->vm()["bdf-time-final"].as<double>() ),
            M_dt( M_application->vm()["bdf-time-step"].as<double>() ),

            M_NS_ALE(new NavierStokes_type( M_application ) )
        {
        }

        void run()
        {
            M_NS_ALE->init();
            NavierStokes_type::element_structure_ptrtype __depl_top = M_NS_ALE->getDeplTop();
            NavierStokes_type::element_structure_ptrtype __depl_bottom = M_NS_ALE->getDeplBottom();
            //M_NS_ALE->runPtFixe();

            for (double time = M_Ti+M_dt;time < M_Tf; time += M_dt)
                {
                    std::cout << "============================================================\n";
                    std::cout << "time: " << time << "s, iteration: ";// << M_bdf_fluid->iteration() << "\n";
#if 1
                    *__depl_top = vf::project( __depl_top->functionSpace(),
                                               elements( __depl_top->functionSpace()->mesh()),
                                               -0.7*sin( time*M_PI/(0.7*2.) )*0.3*vf::sin( M_PI*vf::Px()/4.) );
                    //val( (-0.7*sin(M_bdf_fluid->time()*M_PI/(0.7*2.) ) )*0.3*sin(M_PI*Px()/4.)) );
                    *__depl_bottom = vf::project( __depl_bottom->functionSpace(),
                                                  elements( __depl_bottom->functionSpace()->mesh()),
                                                  +0.7*sin( time*M_PI/(0.7*2.) )*0.3*vf::sin( M_PI*vf::Px()/4.) );
#endif
                    M_NS_ALE->updateDeplacement( __depl_top, __depl_bottom);
                    M_NS_ALE->updateALEmap();
                    //M_NS_ALE->execNewton();
                    M_NS_ALE->runPtFixe();
                    M_NS_ALE->exportResults();
                    M_NS_ALE->updateBdf();
                }

            //M_NS_ALE->runPtFixe();
        }

    private :

        application_ptrtype M_application;

        double M_Ti;
        double M_Tf;
        double M_dt;

        NavierStokes_ptrtype M_NS_ALE;
    };

} //end namespace Life


#endif /* __APPLI_CORE_ALE_NS_H */
